package com.uuah.server.util.store;

import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.uuah.api.lifecycle.IDisposable;
import com.uuah.api.lifecycle.Initialisable;
import com.uuah.api.store.IObjectStore;
import com.uuah.concurrent.DaemonThreadFactory;
import com.uuah.config.i18n.CoreMessages;
import com.uuah.exception.lifecycle.InitialisationException;
import com.uuah.server.api.IUuahContext;
import com.uuah.server.api.context.IUuahContextAware;
import com.uuah.utils.UUID;

public abstract class AbstractMonitoredObjectStore implements IObjectStore,
		Runnable, IUuahContextAware, Initialisable, IDisposable {
	protected final Logger logger = LoggerFactory.getLogger(this.getClass());

	/**
	 * Default constructor for IdempotentInMemoryMessageIdStore.
	 *
	 * @param name
	 *            a name for this store, can be used for logging and
	 *            identification purposes
	 * @param maxEntries
	 *            the maximum number of entries that this store keeps around.
	 *            Specify <em>-1</em> if the store is supposed to be
	 *            "unbounded".
	 * @param entryTTL
	 *            the time-to-live for each message ID, specified in seconds, or
	 *            <em>-1</em> for entries that should never expire. <b>DO
	 *            NOT</b> combine this with an unbounded store!
	 * @param expirationInterval
	 *            the interval for periodic bounded size enforcement and entry
	 *            expiration, specified in seconds. Arbitrary positive values
	 *            between 1 second and several hours or days are possible, but
	 *            should be chosen carefully according to the expected message
	 *            rate to prevent OutOfMemory conditions.
	 */
	protected ScheduledThreadPoolExecutor scheduler;
	protected int maxEntries = 4000;
	protected int entryTTL = -1;
	protected int expirationInterval = 1000;
	protected String name;
	protected IUuahContext context;

	public void initialise() throws InitialisationException {
		if (name == null) {
			name = UUID.getTimeBasedUUIDString();
		}

		if (expirationInterval <= 0) {
			throw new IllegalArgumentException(CoreMessages
					.propertyHasInvalidValue("expirationInterval",
							new Integer(expirationInterval)).toString());
		}

		if (scheduler == null) {
			this.scheduler = new ScheduledThreadPoolExecutor(1);
			scheduler.setThreadFactory(new DaemonThreadFactory(name
					+ "-Monitor"));
			scheduler.scheduleWithFixedDelay(this, 0, expirationInterval,
					TimeUnit.MILLISECONDS);
		}
	}

	public final void run() {
		expire();
	}

	public void dispose() {
		if (scheduler != null) {
			scheduler.shutdown();
		}
	}

	public void setEntryTTL(int entryTTL) {
		this.entryTTL = entryTTL;
	}

	public void setExpirationInterval(int expirationInterval) {
		this.expirationInterval = expirationInterval;
	}

	public void setMaxEntries(int maxEntries) {
		this.maxEntries = maxEntries;
	}

	public void setScheduler(ScheduledThreadPoolExecutor scheduler) {
		this.scheduler = scheduler;
	}

	public void setName(String id) {
		this.name = id;
	}

	public void setUuahContext(IUuahContext context) {
		this.context = context;
	}

	public int getEntryTTL() {
		return entryTTL;
	}

	public int getExpirationInterval() {
		return expirationInterval;
	}

	public int getMaxEntries() {
		return maxEntries;
	}

	public String getName() {
		return name;
	}

	public ScheduledThreadPoolExecutor getScheduler() {
		return scheduler;
	}

	protected abstract void expire();

}
